namespace AgentJohnson
{
  using System;
  using System.Collections.Generic;
  using System.Text;
  using System.Xml;
  using JetBrains.Application;
  using JetBrains.Application.Components;
  using JetBrains.Application.Configuration;
  using JetBrains.DataFlow;
  using Resharper.Abstractions.Settings;
  using Resharper.Abstractions.Shell;

  /// <summary>Represents the Favorite Files Settings.</summary>
  [ShellComponent(ProgramConfigurations.VS_ADDIN)]
  public class IntroduceStringConstantSettings : SettingsBase, IDisposable
  {
    /// <summary>Initializes a new instance of the <see cref="IntroduceStringConstantSettings"/> class.</summary>
    /// <param name="shellSettingsComponent">The shell settings component.</param>
    public IntroduceStringConstantSettings(ShellSettingsComponent shellSettingsComponent)
    {
      this.ShellSettingsComponent = shellSettingsComponent;
      shellSettingsComponent.LoadSettings(this, XmlExternalizationScope.WorkspaceSettings, "IntroduceString");
    }

    /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
    public void Dispose()
    {
      this.ShellSettingsComponent.SaveSettings(this, XmlExternalizationScope.WorkspaceSettings, "IntroduceString");
    }

    #region Constants and Fields

    /// <summary>The _class names.</summary>
    private List<string> classNames;

    #endregion

    #region Properties

    /// <summary>
    /// Gets the instance.
    /// </summary>
    /// <value>The instance.</value>
    public static IntroduceStringConstantSettings Instance
    {
      get
      {
        return ShellManager.GetComponent<IntroduceStringConstantSettings>();
      }
    }

    /// <summary>
    /// Gets or sets the class names.
    /// </summary>
    /// <value>The class names.</value>
    public List<string> ClassNames
    {
      get
      {
        if (this.classNames == null)
        {
          this.Initialize();
        }

        return this.classNames;
      }

      set
      {
        this.classNames = value;
      }
    }

    /// <summary>
    /// Gets or sets a value indicating whether [generate XML comment].
    /// </summary>
    /// <value><c>true</c> if [generate XML comment]; otherwise, <c>false</c>.</value>
    [XmlExternalizable(false)]
    public bool GenerateXmlComment { get; set; }

    /// <summary>
    /// Gets or sets the replace spaces mode.
    /// </summary>
    /// <value>The replace spaces mode.</value>
    [XmlExternalizable(0)]
    public int ReplaceSpacesMode { get; set; }

    /// <summary>
    /// Gets or sets the class names in a serializable format.
    /// </summary>                             
    /// <remarks>This is for serialization only.</remarks>
    /// <value>The class names.</value>
    [XmlExternalizable("")]
    public string SerializableClassNames
    {
      get
      {
        var result = new StringBuilder();

        var first = true;
        foreach (var className in this.ClassNames)
        {
          if (!first)
          {
            result.Append("|");
          }

          first = false;

          result.Append(className);
        }

        return result.ToString();
      }

      set
      {
        this.classNames = new List<string>();

        if (string.IsNullOrEmpty(value))
        {
          return;
        }

        var classes = value.Split('|');

        foreach (var className in classes)
        {
          if (!string.IsNullOrEmpty(className))
          {
            this.classNames.Add(className);
          }
        }
      }
    }

    #endregion

    #region Public Methods

    /// <summary>Reads the settings.</summary>
    /// <param name="doc">The doc.</param>
    public void ReadSettings(XmlDocument doc)
    {
      var node = doc.SelectSingleNode("/settings/introducestringconstant");
      if (node == null)
      {
        return;
      }

      this.GenerateXmlComment = GetAttributeString(node, "generatexmlcomment") == "true";
      this.ReplaceSpacesMode = int.Parse(GetAttributeString(node, "replacespacesmode"));

      this.classNames.Clear();

      var classes = node.SelectNodes("class");
      if (classes == null)
      {
        return;
      }

      foreach (XmlNode xmlNode in classes)
      {
        this.classNames.Add(xmlNode.InnerText);
      }
    }

    /// <summary>Writes the settings.</summary>
    /// <param name="writer">The writer.</param>
    public void WriteSettings(XmlTextWriter writer)
    {
      writer.WriteStartElement("introducestringconstant");

      writer.WriteAttributeString("generatexmlcomment", this.GenerateXmlComment ? "true" : "false");

      writer.WriteAttributeString("replacespacesmode", this.ReplaceSpacesMode.ToString());

      foreach (var className in this.ClassNames)
      {
        writer.WriteElementString("class", className);
      }

      writer.WriteEndElement();
    }

    #endregion

    #region Methods

    /// <summary>Initializes this instance.</summary>
    protected override void Initialize()
    {
      this.classNames = new List<string>();
    }

    /// <summary>Gets the attribute.</summary>
    /// <param name="node">The node.</param>
    /// <param name="name">The name.</param>
    /// <returns>The attribute.</returns>
    private static string GetAttributeString(XmlNode node, string name)
    {
      var attributes = node.Attributes;
      if (attributes == null)
      {
        return string.Empty;
      }

      var attribute = attributes[name];

      return attribute == null ? string.Empty : (attribute.Value ?? string.Empty);
    }

    #endregion
  }
}